#include "lvgl/lvgl.h"
#include <cjson/cJSON.h>

//Q: ✅字符数组长度定义：分配一个足够的缓冲区，避免溢出，同时又不浪费太多内存
// 1. 典型 OAuth Token 的长度范围
// 常见 OAuth2 平台（百度、微信、GitHub、Google、AWS等）返回的 token 长度通常在：
// access_token：40～200 字节之间
// refresh_token：50～200 字节之间
// scope：几十字节（如 "basic profile email"）
// 因此设置为 256 字节几乎能覆盖所有主流平台的 token 长度
// 2. 方便对齐、内存布局合理
// 256 是 2 的幂（2⁸），对齐和分配在嵌入式系统或内存受限场景中比较高效。
// 分配结构体内存时，编译器通常会对齐到字节边界，256 的倍数有助于简化内存布局。
// 3. 安全与简洁的折中
// 如果用动态分配（malloc）虽然节省内存，但在嵌入式或实时系统中管理复杂。
// 固定长度的 char 数组更安全、易用。
// 256 足够应对绝大多数 API，不会轻易溢出。
// ✅ 总结建议
// 场景	                  推荐长度	    说明
// 普通百度/微信 OAuth	   128	        节省内存足够用
// 多平台兼容或未知平台	    256	         安全通用
// 极端安全、未来兼容	    512	         稍大但更保险
#define TOKEN_MAX_LEN 256

//网盘容量信息
typedef struct {
    int errno_code;
    double total_GB;// 总空间大小，单位GB
    double free_GB;// 免费容量，单位GB
    double used_GB;// 已使用大小，单位GB
    bool expire;// 7天内是否有容量到期
    long long request_id;
} StorageInfo;

        //get info result: {"portrait":"88ac436865636b5f4a469935","username":"C***F","is_bind_mobile":"1","is_realname":"1","birthday":"0000-00-00","sex":"1","openid":"oPsAi-xB5dS2MXViilBXesyZSbcwh98"}

//用户信息
typedef struct {
    char openid[64];
    char portrait[32];
    char username[64];
    char birthday[16];
    char sex[8];
    char is_bind_mobile[8];
    char is_realname[8];
} UserInfo;

//授权信息
typedef struct {
    char access_token[TOKEN_MAX_LEN];
    char refresh_token[TOKEN_MAX_LEN];
    uint32_t expires_in;       // 秒
    char scope[TOKEN_MAX_LEN];
} OAuthToken;

//百度网盘开放平台设备码
typedef struct {
    char device_code[65];       // 假设最大64字节UUID + 结束符
    char user_code[32];         // 用户授权码
    char verification_url[128]; // 设备验证URL
    char qrcode_url[256];       // 二维码URL
    int expires_in;             // 有效期（秒）
    //interval：device_code 换 Access Token 轮询间隔时间，单位：秒。轮询次数限制小于 expire_in/interval。
    int interval;               // 轮询间隔（秒）
} DeviceAuthResponse;

//Q: ✅全局变量结构体初始化：
// 将整个结构体静态初始化为0（所有字符数组内容都是 '\0'，所有整数是 0）；
// 相当于手动执行了一次 memset(&g_device_auth, 0, sizeof(DeviceAuthResponse));；
// 初始化发生在程序加载时（不是运行时调用）。改为全局变量后，不需要再memset，因为{0}已经清零了。
// DeviceAuthResponse g_device_auth = {0};//get_code函数获取设备码响应数据
// ✅清空旧值即清空结构体的所有字段，让字符串第一个字节变成 '\0'，数字都变成 0，布尔型变成 false：
// ✅判断全局结构体是否“空”或“未初始化”：memset(&g_device_auth, 0, sizeof(DeviceAuthResponse));
// 结构体不是指针，不能为NULL，所以常见做法是根据关键字段（例如 device_code）是否为空字符串来判断。
// bool is_device_auth_empty() {
//     return g_device_auth.device_code[0] == '\0';
// }
// ✅赋值语句：
// 1️⃣字符数组char *
// strcpy(g_device_auth.qrcode_url, qrcode_url);//❌可能越界
// strncpy(g_device_auth.qrcode_url, qrcode_url, sizeof(qrcode_url) - 1);//✅防止越界的赋值语句
// strncpy(res.device_code, item->valuestring, sizeof(res.device_code) - 1);
// 2️⃣针对整型（int / uint32_t）：g_device_auth.expires_in = item->valueint;
// ✅ 三、其他类型举例
// char[64]	cJSON_IsString(item)	strncpy(obj.xxx, item->valuestring, sizeof(obj.xxx)-1);
// int	cJSON_IsNumber(item)	obj.xxx = item->valueint;
// double	cJSON_IsNumber(item)	obj.xxx = item->valuedouble;
// bool	cJSON_IsBool(item)	obj.xxx = cJSON_IsTrue(item);

// 调用函数时对于struct结构体类型的参数，会复制一份结构体副本，函数内部操作的只是这个拷贝，不会修改原来的结构体变量
// ✅ 传指针参数：config_device_auth_rep(DeviceAuthResponse *g_device_auth, cJSON *json)
// 然后调用：config_device_auth_rep(&g_device_auth, json)，这样函数内修改的字段会直接作用在传递参数的对象上


/**
 * http请求响应数据json解析赋值结构体变量
 * @param DeviceAuthResponse *g_device_auth 响应数据协议对应的结构体，传指针参数，直接修改字段会直接作用在原变量上
 * @param cJSON *json 响应数据json
 * @return void
 */
void config_storage_info_rep(StorageInfo *storage_info, cJSON *json);

/**
 * http请求响应数据json解析赋值结构体变量
 * @param DeviceAuthResponse *g_device_auth 响应数据协议对应的结构体，传指针参数，直接修改字段会直接作用在原变量上
 * @param cJSON *json 响应数据json
 * @return void
 */
void config_device_auth_rep(DeviceAuthResponse *g_device_auth, cJSON *json);

/**
 * http请求响应数据json解析赋值结构体变量
 * @param OAuthToken *g_oauth_token 响应数据协议对应的结构体，传指针参数，直接修改字段会直接作用在原变量上
 * @param cJSON *json 响应数据json
 * @return void
 */
void config_access_token_rsp(OAuthToken *g_oauth_token, cJSON *json);

/**
 * http请求响应数据json解析赋值结构体变量
 * @param UserInfo *user_info 响应数据协议对应的结构体，传指针参数，直接修改字段会直接作用在原变量上
 * @param cJSON *json 响应数据json
 * @return void
 */
void config_info_rsp(UserInfo *user_info, cJSON *json);
